﻿#include "CocosPCH.h"
#include "MatrixTransformer.h"

#define PI (3.14159265)

float MatrixTransformer::getScaleX(AffineTransform &m)
{
	return sqrt(m.a*m.a + m.b*m.b);
}
void MatrixTransformer::setScaleX(AffineTransform &m, float scaleX)
{
	float oldValue = getScaleX(m);
	// avoid division by zero 
	if (oldValue)
	{
		float ratio = scaleX / oldValue;
		m.a *= ratio;
		m.b *= ratio;
	}
	else
	{
		float skewYRad = getSkewYRadians(m);
		m.a = cos(skewYRad) * scaleX;
		m.b = sin(skewYRad) * scaleX;
	}
}
float MatrixTransformer::getScaleY(AffineTransform &m)
{
	return sqrt(m.c*m.c + m.d*m.d);
}

void MatrixTransformer::setScaleY(AffineTransform &m, float scaleY)
{
	float oldValue = getScaleY(m);
	// avoid division by zero 
	if (oldValue)
	{
		float ratio = scaleY / oldValue;
		m.c *= ratio;
		m.d *= ratio;
	}
	else
	{
		float skewXRad = getSkewXRadians(m);
		m.c = -sin(skewXRad) * scaleY;
		m.d =  cos(skewXRad) * scaleY;
	}
}
float MatrixTransformer::getSkewXRadians(AffineTransform &m)
{
	return atan2(-m.c, m.d);
}
void MatrixTransformer::setSkewXRadians(AffineTransform &m, float skewX)
{
	float scaleY = getScaleY(m);
	m.c = -scaleY * sin(skewX);
	m.d =  scaleY * cos(skewX);
}
float MatrixTransformer::getSkewYRadians(AffineTransform &m)
{
	return atan2(m.b, m.a);
} 
void MatrixTransformer::setSkewYRadians(AffineTransform &m, float skewY)
{
	float scaleX = getScaleX(m);
	m.a = scaleX * cos(skewY);
	m.b = scaleX * sin(skewY);
}

float MatrixTransformer::getSkewX(AffineTransform &m)
{
	return atan2(-m.c, m.d) * (180/PI);
}
void MatrixTransformer::setSkewX(AffineTransform &m, float skewX)
{
	setSkewXRadians(m, skewX*(PI/180));
}
float MatrixTransformer::getSkewY(AffineTransform &m)
{
	return atan2(m.b, m.a) * (180/PI);
}

void MatrixTransformer::setSkewY(AffineTransform &m, float skewY)
{
	setSkewYRadians(m, skewY*(PI/180));
}	
float MatrixTransformer::getRotationRadians(AffineTransform &m)
{
	return getSkewYRadians(m);
}
void MatrixTransformer::setRotationRadians(AffineTransform &m, float rotation)
{
	float oldRotation = getRotationRadians(m);
	float oldSkewX = getSkewXRadians(m);
	setSkewXRadians(m, oldSkewX + rotation-oldRotation);
	setSkewYRadians(m, rotation);		
}
float MatrixTransformer::getRotation(AffineTransform &m)
{
	return getRotationRadians(m)*(180/PI);
}
void MatrixTransformer::setRotation(AffineTransform &m, float rotation)
{
	setRotationRadians(m, rotation*(PI/180));
}

void MatrixTransformer::rotateAroundInternalPoint(AffineTransform &m, float x, float y, float angleDegrees)
{
	Vec2 point = Vec2(x, y);
    point = PointApplyAffineTransform(point, m);
	m.tx -= point.x;
	m.ty -= point.y;
	m=AffineTransformRotate(m,angleDegrees*(PI/180));
	m.tx += point.x;
	m.ty += point.y;
}

void MatrixTransformer::rotateAroundExternalPoint(AffineTransform &m, float x, float y, float angleDegrees)
{
	m.tx -= x;
	m.ty -= y;
	m=AffineTransformRotate(m,angleDegrees*(PI/180));
	m.tx += x;
	m.ty += y;
}
void MatrixTransformer::matchInternalPointWithExternal(AffineTransform &m, Vec2 &internalPoint, Vec2 &externalPoint)
{
    Vec2 internalPointTransformed = PointApplyAffineTransform(internalPoint, m);
	float dx = externalPoint.x - internalPointTransformed.x;
	float dy = externalPoint.y - internalPointTransformed.y;	
	m.tx += dx;
	m.ty += dy;
}
void  MatrixTransformer::getGetTSK(AffineTransform& trans, Vec2 &pos, Vec2 &scale, Vec2 &skew)
{
    pos.x = trans.tx;
    pos.y = trans.ty;
    scale.x = MatrixTransformer::getScaleX(trans);
    scale.y = MatrixTransformer::getScaleY(trans);
    skew.x = -MatrixTransformer::getSkewX(trans);
    skew.y = MatrixTransformer::getSkewY(trans);
}
void  MatrixTransformer::getGetTSKRadians(AffineTransform& trans, Vec2 &pos, Vec2 &scale, Vec2 &skew)
{
    pos.x = trans.tx;
    pos.y = trans.ty;
    scale.x = MatrixTransformer::getScaleX(trans);
    scale.y = MatrixTransformer::getScaleY(trans);
    skew.x = -MatrixTransformer::getSkewXRadians(trans);
    skew.y = MatrixTransformer::getSkewYRadians(trans);
}

void MatrixTransformer::getGetMatrix(AffineTransform& trans, Mat4 &matrix)
{
    matrix = Mat4::IDENTITY;

    Vec2 pos; Vec2 scale; Vec2 skew;
    getGetTSK(trans, pos, scale, skew);


    if (skew.x == -skew.y)
    {
        double sine = sin(skew.x);
        double cosine = cos(skew.x);

        matrix.m[0] = scale.x * cosine;
        matrix.m[1] = scale.x * -sine;
        matrix.m[4] = scale.y * sine;
        matrix.m[5] = scale.y * cosine;
    }
    else
    {
        matrix.m[0] = scale.x * cos(skew.y);
        matrix.m[1] = scale.x * sin(skew.y);
        matrix.m[4] = scale.y * sin(skew.x);
        matrix.m[5] = scale.y * cos(skew.x);
    }

    matrix.m[12] = pos.x;
    matrix.m[13] = pos.y;
}